在作業系統的定義中,Thread 是能夠進行排成的最小單位。
每條執行緒負責不同的任務,且他們有各自的優先級,
優先級高的執行緒必須先被執行。
在TI-RTOS中,可分成四種執行緒,依照優先等級最高到低分別是
硬體中斷又稱ISR(Interrupt Service Routine),
不只TI-RTOS,在所有的系統中這應該都是擁有最高優先級的執行緒。
這是由最底層所觸發的事件,用來處理非常緊迫的任務,所以執行時間被嚴格的限制,
在SimplePeripheral 範例中,按鈕偵測就使用到硬體中斷,這個函式的位址在初始化的時候被註冊
void Board_initKeys(keysPressedCB_t appKeyCB)
{
...
// 將函式的位址設定給底層的驅動,
// 當中斷發生(按鈕被按下或放開)時,
// 底層會自己呼叫這個函式。
PIN_registerIntCb(hKeyPins, Board_keyCallback);
...
}
// 當中斷發生(按鈕被按下或放開)時,
// 底層自己會在硬體中斷的執行緒來執行這段程式碼
// 這邊只做簡單的讀寫暫存器和變數
static void Board_keyCallback(PIN_Handle hPin, PIN_Id pinId)
{
keysPressed = 0;
if ( PIN_getInputValue(Board_PIN_BUTTON0) == 0 )
{
keysPressed |= KEY_LEFT;
}
if ( PIN_getInputValue(Board_PIN_BUTTON1) == 0 )
{
keysPressed |= KEY_RIGHT;
}
// 這個啟動定時器的動作,是為了做按鈕的除抖動(Debouncing)
Util_startClock(&keyChangeClock);
}
軟體中斷對於執行時間的要求比硬體中斷稍微寬鬆一些,
但也不是完全不管,執行時間一樣要盡量地短,且不能使用 blocking API。
在這類的執行緒中,建議使用TI-RTOS 提供的 API (XXX_post())
在SimplePeripheral 範例中,
被設定好的定時器時間到,就會產生軟體中斷
static void SimplePeripheral_init(void)
{
...
// 在Simple Peripheral 任務初始化的階段,
// 我們有建立一個定時器,
// 並指定時間到的時候要呼叫的程式碼 SimplePeripheral_clockHandler
Util_constructClock(&clkPeriodic, SimplePeripheral_clockHandler,
SP_PERIODIC_EVT_PERIOD, 0, false, (UArg)&argPeriodic);
...
}
// 定時器時間到的時候,
// 會在軟體中斷的執行緒來執行這段程式碼
static void SimplePeripheral_clockHandler(UArg arg)
{
spClockEventData_t *pData = (spClockEventData_t *)arg;
if (pData->event == SP_PERIODIC_EVT)
{
...
// 這邊還沒看到官方建議的XXX_post(),繼續往下追
SimplePeripheral_enqueueMsg(SP_PERIODIC_EVT, NULL);
}
...
}
// 最後追到這
uint8_t Util_enqueueMsg(Queue_Handle msgQueue,
Event_Handle event,
uint8_t *pMsg)
{
...
// 在這裡也還沒處理要做的事情,
// 而是透過Event_post(),把定時器到期的這個事件發布出來
Event_post(event, UTIL_QUEUE_EVENT_ID);
...
}
// 接著我們來看SimplePeripheral 任務
static void SimplePeripheral_taskFxn(UArg a0, UArg a1)
{
// Initialize application
SimplePeripheral_init();
// Application main loop
for (;;)
{
...
// 這裡是比軟體中斷優先級低一點的Task級別
// 在這邊會一直等待Event,
// 剛在軟體中斷所發出的Event_post 就會在這邊被接收到,
// 然後真正要做的事情,就會在Task 級別的執行緒中來執行
events = Event_pend(syncEvent, Event_Id_NONE, SP_ALL_EVENTS,
ICALL_TIMEOUT_FOREVER);
}
}
這裡的優先級比軟體中斷低,
另外跟軟體中斷最大的不同在於Task 允許等待,
就像剛剛舉的例子,Task 可以卡在Event_pend(),
直到有其他執行緒呼叫Event_post(),
再繼續往下跑就好。
另外,我們可以建立多個Task,
每個Task 都是獨立的Thread,
Task 之間可以使用 TI-RTOS 提供的機制來進行通訊,(例如:Semaphore、Event、Queue、Mailbox)。
當中斷和Task 都沒事做的時候,系統就會來到Idle Task,
以CC26X2來說,就會被允許進入省電模式。